﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Medianamik.Core.Interfaces;
using Medianamik.Core.Sugar;
using Medianamik.Core.Synchronization;

namespace Medianamik.Core
{
    public static class Extensions
    {
        public static T GetValue<T>(this NameValueCollection collection, string key)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            var value = collection[key];
            var type = typeof(T);

            if (string.IsNullOrEmpty(value))
            {
                if (type == typeof(string) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    return default(T);

                throw new ArgumentOutOfRangeException("key");
            }

            if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                var nc = new NullableConverter(type);
                type = nc.UnderlyingType;
            }

            if (type.IsEnum)
                return (T)Enum.Parse(type, value, false);

            var converter = TypeDescriptor.GetConverter(type);

            if (converter.CanConvertFrom(typeof(string)))
            {
                var converted = default(T);

                try
                {
                  converted =  (T)converter.ConvertFrom(value);
                }
                catch 
                {
                }

                return converted;
            }

            return (T)Convert.ChangeType(value, type);
        }

        public static bool EqualsIgnoreCase(this string s1, string s2)
        {
            if (s1 == null)
            {
                return (s2 == null);
            }
            return s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase);
        }

        public static bool Contains(this string str, string value, StringComparison comparison)
        {
            return str.IndexOf(value, comparison) != -1;
        }

        public static IEnumerable<T> NotNull<T>(this IEnumerable<T> pItems) where T : class
        {
            return pItems.Where(i => i != null);
        }

        public static void ForEach<T>(this IEnumerable<T> pItems, Action<T> pAction)
        {
            foreach (T item in pItems)
            {
                pAction(item);
            }
        }

        public static void Each<T>(this IEnumerable<T> ie, Action<T, int> action)
        {
            var i = 0;
            foreach (var e in ie) action(e, i++);
        }

        public static void Redirect(this HttpResponse pResponse, string pUrl, int pResponseCode)
        {
            pResponse.Clear();
            switch (pResponseCode)
            {
                case 301:
                    pResponse.StatusCode = 301;
                    pResponse.StatusDescription = "Moved Permanently";
                    break;
                default:
                case 302:
                    pResponse.StatusCode = 302;
                    pResponse.StatusDescription = "Found";
                    break;
            }

            pResponse.RedirectLocation = pUrl;

            pResponse.ContentType = "text/html";
            pResponse.Write("<html><head><title>Object Moved</title></head>");
            pResponse.Write("<body><h2>" + HttpUtility.HtmlAttributeEncode(pUrl) + "</h2></body></html>");

            pResponse.End();

        }

        public static IEnumerable<Guid> GetParentIDs(this IHierarchicalEntity node, bool inclusive)
        {
            return GetParentIDs(node, inclusive, 0);
        }
        public static IEnumerable<Guid> GetParentIDs(this IHierarchicalEntity node, bool inclusive, int depth)
        {
            return DataUtil.GetBottomToTopNodeIds(node.Path, inclusive, depth);
        }

        public static bool IsEquivalentToTypeProperty(this IProperty interfaceProperty, IProperty typeProperty)
        {
            //Le nom est le même
            //Le DataType est equivalent et s'il faut préciser un MaxLength, celui du type est plus petit ou égal à celui de l'interface
            return String.Compare(interfaceProperty.Name, typeProperty.Name) == 0 &&
               (interfaceProperty.DataType.ID.Equals(DataTypes.NVarcharMax) &&
                typeProperty.DataType.ID.Equals(DataTypes.Varchar) ||
                (interfaceProperty.DataType.ID.Equals(typeProperty.DataType.ID) &&
                 (!typeProperty.DataType.MustSpecifyLength || typeProperty.MaxLength <= interfaceProperty.MaxLength)));
        }


        public static string Format(this string format, params object[] args)
        {
            return string.Format(format, args);
        }

        /// <summary>
        ///     Capitalise la première lettre d'une chaine de caractère.
        ///     Ex.: george harrison => George harrison
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string Capitalize(this string str)
        {
            if (str.Length == 0)
                return str;

            return str.Substring(0, 1).ToUpper() + str.Substring(1);
        }

        /// <summary>
        ///     Convertie la chaîne caractère en TitleCase.
        ///     Ex.: geoRGe hARrison => George Harrison
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToTitleCase(this string str)
        {
            if (str.Length == 0)
                return str;

            return CultureInfo.InvariantCulture.TextInfo.ToTitleCase(str);
        }

        public static string ToAccentInsensitive(this string str)
        {
            if (IsNullOrEmpty(str))
                return str;

            str = str.Normalize(NormalizationForm.FormD);
            StringBuilder sb = new StringBuilder();

            for (int ich = 0; ich < str.Length; ich++)
            {
                UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(str[ich]);
                if (uc != UnicodeCategory.NonSpacingMark)
                {
                    sb.Append(str[ich]);
                }
            }

            return sb.ToString().Normalize(NormalizationForm.FormC).Replace("&", string.Empty);
        }

        //public static bool IsNotNullOrEmpty(this string str)
        //{
        //    return !string.IsNullOrEmpty(str);
        //}

        public static bool IsNullOrEmpty(this string s1)
        {
            return String.IsNullOrEmpty(s1);
        }

        public static string ToCodeSafe(this string str)
        {
            var result = str.ToAccentInsensitive();
            result = Regex.Replace(result, "[^a-zA-Z0-9\\s]", "");
            result = Regex.Replace(result, "[\\s]", "");
            result = result.TrimStart().TrimEnd();
            result = result.Trim();

            return result;
        }

        /// <summary>
        ///     Convertie une chaîne de caractère en array de bytes.
        /// </summary>
        public static byte[] ToBytes(this string str, Encoding charEncoding)
        {
            return charEncoding.GetBytes(str);
        }

        public static void Raise(this EventHandler eventHandler,
                                 object sender, EventArgs e)
        {
            if (eventHandler != null)
            {
                eventHandler(sender, e);
            }
        }

        public static void Raise<T>(this EventHandler<T> eventHandler,
                                    object sender, T e) where T : EventArgs
        {
            if (eventHandler != null)
            {
                eventHandler(sender, e);
            }
        }

        public static IEnumerable<Node> SetInstancesDirty(this IEnumerable<Node> nodeList, bool dirtyValue)
        {
            nodeList.ForEach(n => n.Instances.ForEach(i => i.IsDirty = dirtyValue));
            return nodeList;
        }
    }
}
